#include "LuaValue.hpp"

namespace red {
	LuaValue::LuaValue() : mDataType(LUA_TNIL){
	}

	LuaValue::LuaValue(bool b) : mDataType(LUA_TBOOLEAN){
		mBool = b;
	}

	LuaValue::LuaValue(f32 f) : mDataType(LUA_TNUMBER){
		lua_Number lNum = static_cast<lua_Number>(f);
		mNumber = lNum;
	}

	LuaValue::LuaValue(f64 f) : mDataType(LUA_TNUMBER){
		lua_Number lNum = static_cast<lua_Number>(f);
		mNumber = lNum;
	}

	LuaValue::LuaValue(s32 s) : mDataType(LUA_TNUMBER){
		lua_Number lNum = static_cast<lua_Number>(s);
		mNumber = lNum;
	}

	LuaValue::LuaValue(const std::string &pString) : mDataType(LUA_TSTRING){
		mString = pString;
	}

	LuaValue::LuaValue(const char* pStr) : mDataType(LUA_TSTRING){
		mString = pStr;
	}

	bool LuaValue::RetrieveTable(lua_State* L){
		mTable.clear();
		bool noerror = true;
		for(lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)){
			if(lua_isnumber(L, -1))
				mTable.push_back(LuaValue(lua_tonumber(L, lua_gettop(L))));
			else if(lua_isboolean(L, -1))
				mTable.push_back(LuaValue(lua_toboolean(L, lua_gettop(L))));
			else if(lua_isstring(L, -1))
				mTable.push_back(LuaValue(lua_tostring(L, lua_gettop(L))));
			else if(lua_istable(L, -1)){
				LuaValue val;
				val.RetrieveTable(L);
				mTable.push_back(val);
			} else {
				noerror = false;
				break;
			}
		}

		if(noerror)
			mDataType = LUA_TTABLE;

		return noerror;
	}

	std::string LuaValue::GetTypeName() const{
		switch(mDataType){
		case LUA_TNIL:
			return "nil";
		case LUA_TNUMBER:
			return "number";
		case LUA_TBOOLEAN:
			return "bool";
		case LUA_TSTRING:
			return "string";
		default:
			return "";
		}
	}

	bool LuaValue::ToBool() const{
		if(mDataType == LUA_TBOOLEAN)
			return mBool;
		else
			throw Exception(String("LuaValue : tried to convert a ")+GetTypeName()+" to a bool.");
	}

	std::string LuaValue::ToString() const{
		if(mDataType == LUA_TSTRING)
			return mString;
		else if(mDataType == LUA_TNUMBER)
			return String(mNumber);
		else if(mDataType == LUA_TNIL)
			return "null";
		else if(mDataType == LUA_TBOOLEAN)
			return mBool ? "true" : "false";
		else
			throw Exception(String("LuaValue : tried to convert a ")+GetTypeName()+" to a string.");
	}

	s32 LuaValue::ToInt() const{
		if(mDataType == LUA_TNUMBER)
			return (s32)mNumber;
		else if(mDataType == LUA_TSTRING){
			s32 ret;
			std::istringstream iss(mString);
			if(iss >> ret)
				return ret;
		}
		throw Exception(String("LuaValue : tried to convert a ")+GetTypeName()+" to a int.");
	}

	f32 LuaValue::ToFloat() const{
		if(mDataType == LUA_TNUMBER)
			return (f32)mNumber;
		else if(mDataType == LUA_TSTRING){
			f32 ret;
			std::istringstream iss(mString);
			if(iss >> ret)
				return ret;
		}
		throw Exception(String("LuaValue : tried to convert a ")+GetTypeName()+" to a float.");
	}

	LuaValue LuaValue::operator[](u32 i) const{
		if(mDataType == LUA_TTABLE){
			if(i < mTable.size())
				return mTable[i];
			else
				return LuaValue();
		} 
		throw Exception(String("LuaValue : tried to convert a ")+GetTypeName()+" to a table.");
	}

}
